﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Runtime.Serialization;
using System.Text;
using System.Text.RegularExpressions;

namespace mveEngine
{
	[Serializable]
	public class Data
	{
		public List<Item> Items { get; set; }
	}

	[Serializable]
	public class Item : ISerializable, INotifyPropertyChanged
	{
		public string PrimaryProviderSerieId { get; set; }
		public string Path { get; set; }
		public string Id { get; set; }
		public Entity Type { get; set; }
		public bool IsInError { get; set; }
		
		private bool hasChanged;
		
		public bool HasChanged {
			get
			{
				return this.hasChanged;
			}
			set
			{
				this.hasChanged = value;
				this.OnNotifyPropertyChanged("HasChanged");
				this.OnNotifyPropertyChanged("DataState");
			}
		}
		
		public List<string> VideoFiles { get; set; }
		public List<DataProviderId> ProvidersId { get; set; }
		public bool? Watched { get; set; }
		public string FirstAired { get; set; }
		
		DateTime dateAdded;
		
		public DateTime DateAdded {
			get
			{
				return this.dateAdded;
			}
			
			set
			{
				this.dateAdded = value;
				this.OnNotifyPropertyChanged("DateAdded");
			}
		}

		string title;
		
		public string Title {
			get
			{
				return this.title;
			}
			
			set
			{
				this.title = value;
				this.OnNotifyPropertyChanged("Title");
			}
		}
		
		string originalTitle;
		
		public string OriginalTitle {
			get
			{
				return this.originalTitle;
			}
			
			set
			{
				this.originalTitle = value;
				this.OnNotifyPropertyChanged("OriginalTitle");
			}
		}
		
		int? year;
		
		public int? Year {
			get
			{
				return this.year;
			}
			
			set
			{
				this.year = value;
				this.OnNotifyPropertyChanged("Year");
			}
		}
		
		string overview;
		
		public string Overview {
			get
			{
				return this.overview;
			}
			
			set
			{
				this.overview = value;
				this.OnNotifyPropertyChanged("Overview");
			}
		}
		
		public string SortTitle { get; set; }
		public List<string> TagLines { get; set; }
		
		ObservableCollection<Poster> imagesPaths;
		
		public ObservableCollection<Poster> ImagesPaths {
			get
			{
				return this.imagesPaths;
			}
			
			set
			{
				this.imagesPaths = value;
				this.OnNotifyPropertyChanged("ImagesPaths");
			}
		}
		
		Poster primaryImage;
		
		public Poster PrimaryImage {
			get
			{
				return this.primaryImage;
			}
			
			set
			{
				this.primaryImage = value;
				this.OnNotifyPropertyChanged("PrimaryImage");
			}
		}
		
		Collection<Poster> backdropImagePaths;
		
		public Collection<Poster> BackdropImagePaths {
			get
			{
				return this.backdropImagePaths;
			}
			
			set
			{
				this.backdropImagePaths = value;
				this.OnNotifyPropertyChanged("BackdropImagePaths");
			}
		}
		
		public List<string> Genres { get; set; }
		public ObservableCollection<Actor> Actors { get; set; }
		public List<string> Studios { get; set; }
		public List<string> Countries { get; set; }
		public List<CrewMember> Crew { get; set; }
		
		int? runningTime;
		
		public int? RunningTime {
			get
			{
				return this.runningTime;
			}
			
			set
			{
				this.runningTime = value;
				this.OnNotifyPropertyChanged("RunningTime");
			}
		}
		
		Single? rating;
		
		public Single? Rating {
			get
			{
				return this.rating;
			}
			
			set
			{
				this.rating = value;
				this.OnNotifyPropertyChanged("Rating");
			}
		}
		
		string mPAARating;
		
		public string MPAARating {
			get
			{
				return this.mPAARating;
			}
			
			set
			{
				this.mPAARating = value;
				this.OnNotifyPropertyChanged("MPAARating");
			}
		}
		
		Poster primaryBackdrop;
		
		public Poster PrimaryBackdrop {
			get
			{
				return this.primaryBackdrop;
			}
			
			set
			{
				this.primaryBackdrop = value;
				this.OnNotifyPropertyChanged("PrimaryBackdrop");
			}
		}
		
		public List<Poster> BannersPaths { get; set; }
		public Poster PrimaryBanner { get; set; }
		public string MetadataLocation { get; set; }
		
		public ObservableCollection<string> trailerFiles;
		
		public ObservableCollection<string> TrailerFiles
		{
			get
			{
				return trailerFiles;
			}
			set
			{
				trailerFiles = value;
				OnNotifyPropertyChanged("TrailerFiles");
			}
		}
		
		public string Mediatype { get; set; }
		public string AspectRatio { get; set; }

		string seriesName;
		
		public string SeriesName {
			get
			{
				return this.seriesName;
			}
			
			set
			{
				this.seriesName = value;
				this.OnNotifyPropertyChanged("SeriesName");
			}
		}
		
		string seasonNumber;
		
		public string SeasonNumber {
			get
			{
				return this.seasonNumber;
			}
			
			set
			{
				this.seasonNumber = value;
				this.OnNotifyPropertyChanged("SeasonNumber");
			}
		}
		
		public string EpisodeNumber { get; set; }
		
		
		public int DataState
		{
			get
			{
				int r = 0;
				
				if(Type == Entity.Season)
				{
					if(!string.IsNullOrEmpty(this.SeasonNumber))
					{
						r += 50;
					}
					
					if(PrimaryImage != null &&
					   !string.IsNullOrEmpty(PrimaryImage.Image))
					{
						r += 50;
					}
					
					return r;
				}
				
				if(Type == Entity.Episode)
				{
					if(!string.IsNullOrEmpty(this.Title))
					{
						r += 10;
					}
					
					if (!string.IsNullOrEmpty(Overview))
					{
						r += 40;
					}
					
					if(PrimaryImage != null &&
					   !string.IsNullOrEmpty(PrimaryImage.Image))
					{
						r += 50;
					}
					
					return r;
				}
				
				if (ImagesPaths.Any())
					r += 25;
				if (BackdropImagePaths.Any() || Type == Entity.Episode)
					r += 25;
				if (!string.IsNullOrEmpty(Overview))
					r += 10;
				if (Rating.IsValidRating() && RunningTime.IsValidRunningTime())
					r += 10;
				if (Year != null)
					r += 10;
				if (Actors.Count!=0 && Crew.IsNonEmpty())
					r += 10;
				if (Genres != null && Genres.Count > 0)
					r += 10;
				return r;
			}
		}

		//Constructor
		public Item(Item i) : this()
		{
			this.Title = i.Title;
			this.OriginalTitle = i.OriginalTitle;
			this.SortTitle = i.SortTitle;
			this.TagLines = i.TagLines;
			this.Path = i.Path;
			this.VideoFiles = i.VideoFiles;
			this.DateAdded = i.DateAdded;
			this.Overview = i.Overview;
			if (i.ProvidersId != null) this.ProvidersId = new List<DataProviderId>(i.ProvidersId);
			if (i.Actors != null) this.Actors = new ObservableCollection<Actor>(i.Actors);
			if (i.Studios != null) this.Studios = new List<string>(i.Studios);
			if (i.Countries != null) this.Countries = new List<string>(i.Countries);
			if (i.BackdropImagePaths != null) this.BackdropImagePaths = new Collection<Poster>(i.BackdropImagePaths);
			if (i.ImagesPaths != null) this.ImagesPaths = new ObservableCollection<Poster>(i.ImagesPaths);
			if (i.Genres != null) this.Genres = new List<string>(i.Genres);
			if (i.TrailerFiles != null) this.TrailerFiles = new ObservableCollection<string>(i.TrailerFiles);
			this.HasChanged = i.HasChanged;
			this.Id = i.Id;
			this.Rating = i.Rating;
			this.RunningTime = i.RunningTime;
			this.Type = i.Type;
			this.Year = i.Year;
			this.SeriesName = i.SeriesName;
			this.SeasonNumber = i.SeasonNumber;
			this.EpisodeNumber = i.EpisodeNumber;
			this.MetadataLocation = i.MetadataLocation;
			this.BannersPaths = i.BannersPaths;
			this.MPAARating = i.MPAARating;
			this.Mediatype = i.Mediatype;
			this.AspectRatio = i.AspectRatio;
			this.Watched = i.Watched;
			this.Crew = i.Crew;
			this.PrimaryProviderSerieId = i.PrimaryProviderSerieId;

		}
		public Item()
		{
			if (this.Actors == null) {
				this.Actors = new ObservableCollection<Actor>();
			}
			
			if (this.TrailerFiles == null) {
				this.TrailerFiles = new ObservableCollection<string>();
			}
			if(this.imagesPaths== null)
			{
				this.imagesPaths = new ObservableCollection<Poster>();
			}
			
			if (this.backdropImagePaths == null) {
				this.backdropImagePaths = new Collection<Poster>();
			}
		}
		
		public Item(SerializationInfo info, StreamingContext context) : this()
		{
			SerializationReader sr = SerializationReader.GetReader (info);

			var actors = sr.ReadObject() as List<Actor>;
			if(actors!=null)
			{
				this.Actors =new ObservableCollection<Actor>(actors);
			}
			
			this.AspectRatio = sr.ReadString();
			this.BackdropImagePaths = sr.ReadObject() as Collection<Poster>;
			this.BannersPaths = sr.ReadObject() as List<Poster>;
			this.Countries = sr.ReadObject() as List<string>;
			this.Crew = sr.ReadObject() as List<CrewMember>;
			this.DateAdded = sr.ReadDateTime();
			this.EpisodeNumber = sr.ReadString();
			this.Genres = sr.ReadObject() as List<string>;
			this.Id = sr.ReadString();
			this.ImagesPaths = sr.ReadObject() as ObservableCollection<Poster>;
			this.MetadataLocation = sr.ReadString();
			this.MPAARating = sr.ReadString();
			this.OriginalTitle = sr.ReadString();
			this.Overview = sr.ReadString();
			this.Path = sr.ReadString();
			this.PrimaryBackdrop = sr.ReadObject() as Poster;
			this.PrimaryBanner = sr.ReadObject() as Poster;
			this.PrimaryImage = sr.ReadObject() as Poster;
			this.ProvidersId = sr.ReadObject() as List<DataProviderId>;
			this.Rating = sr.ReadObject() as float?;
			this.RunningTime = sr.ReadObject() as int?;
			this.SeasonNumber = sr.ReadString();
			this.SeriesName = sr.ReadString();
			this.SortTitle = sr.ReadString();
			this.Studios = sr.ReadObject() as List<string>;
			this.TagLines = sr.ReadObject() as List<string>;
			this.Title = sr.ReadString();
			
			var trailers = sr.ReadObject() as List<string>;
			
			if(trailers!=null)
			{
				this.TrailerFiles = new ObservableCollection<string>(trailers);
			}
			
			this.Type = (Entity)sr.ReadObject();
			this.VideoFiles = sr.ReadObject() as List<string>;
			this.Watched = sr.ReadObject() as bool?;
			this.Year = sr.ReadObject() as int?;
			this.Mediatype = sr.ReadString();
			this.PrimaryProviderSerieId = sr.ReadString();
			this.FirstAired = sr.ReadString();
		}
		
		public void GetObjectData(SerializationInfo info, StreamingContext context)
		{
			SerializationWriter sw = SerializationWriter.GetWriter ();
			sw.WriteObject(this.Actors.ToList());
			sw.Write(this.AspectRatio);
			sw.WriteObject(this.BackdropImagePaths);
			sw.WriteObject(this.BannersPaths);
			sw.WriteObject(this.Countries);
			sw.WriteObject(this.Crew);
			sw.Write(this.DateAdded);
			sw.Write(this.EpisodeNumber);
			sw.WriteObject(this.Genres);
			sw.Write(this.Id);
			sw.WriteObject(this.ImagesPaths);
			sw.Write(this.MetadataLocation);
			sw.Write(this.MPAARating);
			sw.Write(this.OriginalTitle);
			sw.Write(this.Overview);
			sw.Write(this.Path);
			sw.WriteObject(this.PrimaryBackdrop);
			sw.WriteObject(this.PrimaryBanner);
			sw.WriteObject(this.PrimaryImage);
			sw.WriteObject(this.ProvidersId);
			sw.WriteObject(this.Rating);
			sw.WriteObject(this.RunningTime);
			sw.Write(this.SeasonNumber);
			sw.Write(this.SeriesName);
			sw.Write(this.SortTitle);
			sw.WriteObject(this.Studios);
			sw.WriteObject(this.TagLines);
			sw.Write(this.Title);
			sw.WriteObject(this.TrailerFiles.ToList());
			sw.WriteObject(this.Type);
			sw.WriteObject(this.VideoFiles);
			sw.WriteObject(this.Watched);
			sw.WriteObject(this.Year);
			sw.Write(this.Mediatype);
			sw.Write(this.PrimaryProviderSerieId);
			sw.Write(this.FirstAired);
			
			sw.AddToInfo(info);
		}
		
		public event PropertyChangedEventHandler PropertyChanged;
		
		protected void OnNotifyPropertyChanged(string propertyName)
		{
			if (this.PropertyChanged!=null) {
				this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
			}
		}
	}

	[Serializable]
	public class Actor : ISerializable, INotifyPropertyChanged
	{
		public string Name { get; set; }
		string role;
		
		public string Role {
			get { return role; }
			set {
				role = value;
				this.OnPropertyChanged("Role");
			}
		}
		string imagePath;
		
		public string ImagePath {
			get { return imagePath; }
			set {
				imagePath = value;
				this.OnPropertyChanged("ImagePath");
			}
		}
		
		public Actor()
		{
			
		}
		
		public Actor(SerializationInfo info, StreamingContext context)
		{
			SerializationReader sr = SerializationReader.GetReader (info);
			this.Name = sr.ReadString();
			this.Role = sr.ReadString();
			this.ImagePath = sr.ReadString();
		}
		
		public void GetObjectData(SerializationInfo info, StreamingContext context)
		{
			SerializationWriter sw = SerializationWriter.GetWriter ();
			sw.Write(this.Name);
			sw.Write(this.Role);
			sw.Write(this.ImagePath);
			
			sw.AddToInfo(info);
		}
		
		public event PropertyChangedEventHandler PropertyChanged;
		
		protected void OnPropertyChanged(string propertyName)
		{
			if (this.PropertyChanged!=null) {
				this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
			}
		}
	}

	[Serializable]
	public class CrewMember : ISerializable
	{
		public string Name { get; set; }
		public string Activity { get; set; }
		
		public CrewMember()
		{
			
		}
		
		public CrewMember(SerializationInfo info, StreamingContext context)
		{
			SerializationReader sr = SerializationReader.GetReader (info);
			this.Name = sr.ReadString();
			this.Activity = sr.ReadString();
		}
		
		public void GetObjectData(SerializationInfo info, StreamingContext context)
		{
			SerializationWriter sw = SerializationWriter.GetWriter ();
			sw.Write(this.Name);
			sw.Write(this.Activity);
			
			sw.AddToInfo(info);
		}
	}

	[Serializable]
	public class DataProviderId
	{
		public string Name { get; set; }
		public string Id { get; set; }
		public string Url { get; set; }
	}

	[Serializable]
	public enum Entity
	{
		Movie,
		Series,
		Season,
		Episode,
		Folder
	}

	[Serializable]
	public class Poster : ISerializable, INotifyPropertyChanged
	{
		string thumb;
		
		public string Thumb {
			get
			{
				return this.thumb;
			}
			
			set
			{
				this.thumb = value;
				this.OnNotifyPropertyChanged("Thumb");
			}
		}
		
		string image;
		
		public string Image {
			get
			{
				return this.image;
			}
			
			set
			{
				this.image = value;
				this.OnNotifyPropertyChanged("Image");
			}
		}
		string id;
		
		public string Id {
			get
			{
				return this.id;
			}
			
			set
			{
				this.id = value;
				this.OnNotifyPropertyChanged("Id");
			}
		}
		
		string width;
		
		public string Width {
			get
			{
				return this.width;
			}
			
			set
			{
				this.width = value;
				this.OnNotifyPropertyChanged("Width");
			}
		}
		
		string height;
		
		public string Height {
			get
			{
				return this.height;
			}
			
			set
			{
				this.height = value;
				this.OnNotifyPropertyChanged("Height");
			}
		}
		
		bool isChecked;
		
		public bool Checked {
			get
			{
				return this.isChecked;
			}
			
			set
			{
				this.isChecked = value;
				this.OnNotifyPropertyChanged("Checked");
			}
		}

		public Poster()
		{ }

		//Constructor
		public Poster(Poster p)
		{
			this.Checked = p.Checked;
			this.height = p.height;
			this.Id = p.Id;
			this.Image = p.Image;
			this.Thumb = p.Thumb;
			this.width = p.width;
		}
		
		public Poster(SerializationInfo info, StreamingContext context)
		{
			SerializationReader sr = SerializationReader.GetReader (info);
			this.Thumb = sr.ReadString();
			this.Image = sr.ReadString();
			this.Id = sr.ReadString();
			this.width = sr.ReadString();
			this.height = sr.ReadString();
			this.Checked = sr.ReadBoolean();
		}
		
		public void GetObjectData(SerializationInfo info, StreamingContext context)
		{
			SerializationWriter sw = SerializationWriter.GetWriter ();
			sw.Write(this.Thumb);
			sw.Write(this.Image);
			sw.Write(this.Id);
			sw.Write(this.width);
			sw.Write(this.height);
			sw.Write(this.Checked);
			
			sw.AddToInfo(info);
		}
		
		public event PropertyChangedEventHandler PropertyChanged;
		
		protected void OnNotifyPropertyChanged(string propertyName)
		{
			if (this.PropertyChanged!=null) {
				
				this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
			}
		}
	}
}
